﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;

namespace Cubicle.Core.Shared
{
    public class SelfUpdatingCatalog
    {
        private static readonly List<string> _loadedAssemblies = new List<string>();

        public static readonly AggregateCatalog AggCatalog = new AggregateCatalog();

        static SelfUpdatingCatalog()
        {

            // Cache loaded assemblies
            foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
                if (!asm.ReflectionOnly && !asm.IsDynamic)
                    AddAssembly(asm.CodeBase);

            // Hook event to auto update type registry
            AppDomain.CurrentDomain.AssemblyLoad += AutoCache;

            // Cache files in base directory
            foreach (var location in new[] { "." /*, ".\bin"*/ })
            {
                var dir = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, location);
                if (!Directory.Exists(dir)) continue;
                var files = Directory.EnumerateFiles(dir, "*.dll", SearchOption.TopDirectoryOnly)
                                     .Union(Directory.EnumerateFiles(dir, "*.exe", SearchOption.TopDirectoryOnly));
                foreach (var file in files) 
                    AddAssembly(new Uri(Path.GetFullPath(file)).LocalPath);
            }
        }

        private static void AutoCache(object sender, AssemblyLoadEventArgs args)
        {
            if (args.LoadedAssembly.IsDynamic) return;
            AddAssembly(args.LoadedAssembly.CodeBase);
        }

        public static void AddAssembly(string codebase)
        {
            if (codebase == null) return;
            codebase = new Uri(codebase).LocalPath.Normalize().ToLower();
            if (_loadedAssemblies.Any(x => x.Equals(codebase))) return;
            _loadedAssemblies.Add(codebase);
            AggCatalog.Catalogs.Add(new AssemblyCatalog(codebase));
        }

    }
}